//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#ifndef __ELASTOS_ATA_H__
#define __ELASTOS_ATA_H__

enum {
    IDEPrimaryChannel_IoBase    = 0x1f0,
    IDEPrimaryChannel_Irq       = 14,

    IDESecondaryChannel_IoBase  = 0x170,
    IDESecondaryChannel_Irq     = 15,
};

#define SECTOR_SHIFT        9
#define SECTOR_SIZE         ((uint_t)(1 << SECTOR_SHIFT))
#define SECTOR_MASK         (SECTOR_SIZE - 1)
#define SECTOR_COUNT_SIZE   256

//
// IDE registers
//
// Command Block Registers' port
#define IDEPORT_DATA(base)              ((base) + 0)
#define IDEPORT_ERROR(base)             ((base) + 1)
#define IDEPORT_SECTOR_COUNT(base)      ((base) + 2)
#define IDEPORT_SECTOR_NUMBER(base)     ((base) + 3)
#define IDEPORT_CYLINDER_LOW(base)      ((base) + 4)
#define IDEPORT_CYLINDER_HIGH(base)     ((base) + 5)
#define IDEPORT_DRIVE_HEAD(base)        ((base) + 6)
#define IDEPORT_STATUS(base)            ((base) + 7)
#define IDEPORT_COMMAND(base)           ((base) + 7)

// Control Block Registers' port
#define IDEPORT_ALTERNATE_STATUS(base)  ((base) + 0x206)
#define IDEPORT_DEVICE_CONTROL(base)    ((base) + 0x206)
#define IDEPORT_DRIVE_ADDRESS(base)     ((base) + 0x207)

// Error Register
#define ER_BBK      __8BIT(7)   // Bad block mark detected in the requested
                                // sector's ID field
#define ER_UNC      __8BIT(6)   // Uncorrectable data error encountered
#define ER_MC       __8BIT(5)   // (Media Change) shall be set to one when
                                // the device detects media has been inserted.
#define ER_IDNF     __8BIT(4)   // Requested sector's ID field not found
#define ER_MCR      __8BIT(3)   // (Media Change Request) shall be set to one
                                // if the eject button is pressed by the user
                                // and detected by the device.
#define ER_ABRT     __8BIT(2)   // Command aborted due to drive status error or
                                // invalid command
#define ER_TK0NF    __8BIT(1)   // Track 0 not found during execution of
                                // Recalibrate command
#define ER_AMNF     __8BIT(0)   // Data address mark not found after correct
                                // ID field found

// Drive/Head Register
#define DHR_LBA     __8BIT(6)
#define DHR_DEV     __8BIT(4)   // 0 to select primary drive,
                                // 1 to select secondary drive
#define DHR_(bits)  (__8BIT(7) | __8BIT(5) | (bits))

// Status Register
#define SR_BSY      __8BIT(7)   // Busy bit. Set by the controller logic of the
                                // drive when ever the drive has access to and
                                // the host is locked out of the Command Block
                                // Registers.
#define SR_DRDY     __8BIT(6)   // Drive Ready bit. Indicates that the drive
                                // is ready to accept commands.
#define SR_DF       __8BIT(5)   // Drive Fault bit.
#define SR_DSC      __8BIT(4)   // Drive Seek Complete bit. This bit is set
                                // when a seek operation is complete and the
                                // heads are settled over a track.
#define SR_DRQ      __8BIT(3)   // Data Request bit. When set it indicates that
                                // the drive is ready to transfer a word or byte
                                // of data between the host and the data port.
#define SR_CORR     __8BIT(2)   // Corrected Data bit. When a correctable data
                                // error has been encountered and the data has
                                // been corrected, this bit is set. This
                                // condition does not terminate a multi sector
                                // read operation.
#define SR_IDX      __8BIT(1)   // Index bit. Set when the index mark is
                                // detected once per disk revolution.
#define SR_ERR      __8BIT(0)   // Error bit. When set indicates that the
                                // previous command ended in an error. The other
                                // bits in the Error Register and Status
                                // Register contain additional information
                                // about the cause of the error.

// Device Control Register
#define DCR_SRST    __8BIT(2)   // Host Software Reset bit. When this bit is set
                                // the drive is held reset. If two drives are
                                // daisy chained on the interface, this bit
                                // resets both drives simultaneously.
#define DCR_nIEN    __8BIT(1)   // Drive Interrupt Enable bit. The enable bit
                                // for the drive interrupt to the host. When
                                // nIEN is 0 or the drive is selected the host
                                // interrupt signal INTRQ is enabled through a
                                // tri state buffer to the host. When nIEN is 1
                                // or the drive is not selected the host
                                // interrupt signal INTRQ is in a hig
                                // himpedance state regardless of the presence
                                // or absence of a pending interrupt.
#define DCR_(bits)  (__8BIT(3) | (bits))

// IDE Commands
enum {
    IDECommand_ExecuteDriveDiagnostics          = 0x90,
    IDECommand_IdentifyDevice                   = 0xec,
    IDECommand_InitializeDeviceParameters       = 0x91,
    IDECommand_ReadSectors                      = 0x20,
    IDECommand_ReadSectorsWithoutRetry          = 0x21,
    IDECommand_ReadVerifySectors                = 0x40,
    IDECommand_ReadVerifySectorsWithoutRetry    = 0x41,
    IDECommand_Seek                             = 0x70,
    IDECommand_WriteSectors                     = 0x30,
    IDECommand_WriteSectorsWithoutRetry         = 0x31,
    IDECommand_NOP                              = 0x00,
};

enum {
    // When this code is in the Device 0 Error register
    DiagnosticCode_Device0Passed_Device1PassedOrNotPresent  = 0x01,
    // 0x00, 0x02-0x7f      Device 0 failed, Device 1 passed or not present
    DiagnosticCode_Device0Passed_Device1Failed              = 0x81,
    // 0x80, 0x82-0xff      Device 0 failed, Device 1 failed
    DiagnosticCode_Device0Failed_Device1Failed              = 0x80,

    // When this code is in the Device 1 Error register
    // Note: If Device 1 is not present, the host may see the information from
    // Device 0 even though Device 1 is selected.
    DiagnosticCode_Device1Passed    = 0x01,
    // 0x00, 0x02-0x7f      Device 1 failed
};

enum {
    IDECapability_DMASupported  = __16BIT(8),
    IDECapability_LBASupported  = __16BIT(9),
};

typedef struct IDEDeviceInfo
{
    uint16_t    u16GeneralConfig;
    uint16_t    u16NumberOfLogicalCylinders;
    uint16_t    u16Reserved_2;
    uint16_t    u16NumberOfLogicalHeads;
    uint16_t    u16NumberOfUnformattedBytesPerLogicalTrack; // Retired
    uint16_t    u16NumberOfUnformattedBytesPerSector;       // Retired
    uint16_t    u16NumberOfLogicalSectorsPerTrack;
    uint16_t    u16Reserved_7_9[3];

    uint8_t     u8SerialNumber[20];
    uint16_t    u16ControllerType;  // Retired
    uint16_t    u16BufferSize;      // Retired
    uint16_t    u16NumberOfECCBytes; // passed to host on R/W long operations.
    uint8_t     u8FirmwareRevision[8];
    uint8_t     u8ModelNumber[40];
    uint16_t    u16RWMultiplesImplemented;
    uint16_t    u16DoubleWordIO;            // Reserved
    uint16_t    u16Capability;
    uint16_t    u16Reserved_50;
    uint16_t    u16MinimumPIODataTransferCycleTime; // in nsec
    uint16_t    u16MinimumDMADataTransferCycleTime; // in nsec
    uint16_t    u16Reserved_53;
    uint16_t    u16NumberOfCurrentLogicalCylinders;
    uint16_t    u16NumberOfCurrentLogicalHeads;
    uint16_t    u16NumberOfCurrentLogicalSectorsPerTrack;
    uint16_t    u16NumberOfCurrentLogicalSectorsLow;
    uint16_t    u16NumberOfCurrentLogicalSectorsHigh;
    uint16_t    u16CurrentMultipleSector;
    uint32_t    u32NumberOfLBASectors;
    uint16_t    u16SingleWordDMAMode;
    uint16_t    u16MultipleWordDMAMode;
    uint16_t    u16Reserved_64_255[192];
};

typedef enum AddressingMode
{
    AddressingMode_CHS  = 0,
    AddressingMode_LBA  = DHR_LBA,
};

#endif // __ELASTOS_ATA_H__
